package global;

import java.io.IOException;

import btree.AddFileEntryException;
import btree.ConstructPageException;
import btree.GetFileEntryException;
import bufmgr.HashEntryNotFoundException;
import bufmgr.InvalidFrameNumberException;
import bufmgr.PageUnpinnedException;
import bufmgr.ReplacerException;
import diskmgr.PCounter;
import heap.HFBufMgrException;
import heap.HFDiskMgrException;
import heap.HFException;
import heap.Tuple;
import iterator.FileScan;
import iterator.FldSpec;
import va.VAEntry;
import va.VAIndexAdapter;

public class BatchIndex implements GlobalConst 
{
	private VAIndexAdapter[] indexes;
	public int IndexCount()
	{
		if (indexes!=null) {
			return indexes.length;
		}
		return 0;
	}
	// will get information for indexes associated with a relation
	public BatchIndex(String relName, boolean recreateIndexes) throws HFException, HFBufMgrException, HFDiskMgrException, GetFileEntryException, ConstructPageException, AddFileEntryException, IOException
	{
		IDXSchema[] idx;
		idx = IDXSchema.GetIndexes(relName);
		this.indexes = new VAIndexAdapter[idx.length];
		for (int i=0; i<idx.length; i++)
		{
			indexes[i] = new VAIndexAdapter(idx[i], recreateIndexes);
		}
	}

    // Closes all the adapters to make sure no buffer pages are left pinned

    public void close() throws PageUnpinnedException, InvalidFrameNumberException, HashEntryNotFoundException, ReplacerException {
        for (int i = 0; i < this.indexes.length; i++) {
            indexes[i].close();
        }
    }

    // Adds tuples to the relevant indexes
	
	public boolean UpdateIndexes(Tuple t, RID rid)
	{
		boolean successful = true;
		for (int i=0; i<indexes.length; i++)
		{
			successful = indexTuple(indexes[i], t, rid) && successful;
		}
		return successful;
	}

    // Creates indexes for a relation
	
	public boolean CreateIndexes(Schema relSchema)
	{
		boolean successful = true;
		for (int i=0; i<indexes.length; i++)
		{
			successful = createVAIndex(relSchema, indexes[i]) && successful;
		}
		return successful;
	}

    // Creates an index for a relation
	
	public static boolean CreateIndex(String relName, IDXSchema index) throws IOException
	{
		boolean successful = true;
		
		try
		{
			Schema relSchema = Schema.getSchema(relName);
			VAIndexAdapter adapter = new VAIndexAdapter(index, true);
			successful = createVAIndex(relSchema, adapter);
			// save the index information
			index.InsertIndex();
		}
		catch (Exception ex) { successful = false; }

		return successful;
	}

    // Creates the va index
	
	public static boolean createVAIndex(Schema relSchema, VAIndexAdapter index)
	{
		boolean successful = true;
		
		// scan file and index each tuple
	    FileScan fs = null;
	    int tupleCnt = 0;
	    try
	    {
		    FldSpec[] projlist = CommandLine.getFldSpecForAll(relSchema.attrType);
		    fs = new FileScan(relSchema.dbName, relSchema.attrType, relSchema.attrSize, 
		    		(short)relSchema.attrType.length, relSchema.attrType.length, projlist, null);
		    Tuple tuple = Batch.prepTuple(relSchema.attrType.length, relSchema.attrType, relSchema.attrSize);
		    while ((tuple = fs.get_next()) != null )
		    {
			    RID rid = fs.scan.currentRID;
			    if (indexTuple(index, tuple, rid))
			    {
			    	tupleCnt++;
			    }
			    else
			    {
			    	successful = false;
			    }
		    }
		    // must close b-tree indexes before flushing pages
		    index.close();
	    }
	    catch (Exception e) {
	    	System.err.println("Error creating index file: " + e.getMessage());
	    	successful = false;
	    }
	    finally {
	    	if (fs!=null) {
	    		fs.close();
	    	}
	    }
	    
	    if (successful)
	    {
		    // output statistics
	    	System.out.format("Indexed %d tuples in the %s index file.\n", tupleCnt, index.Index.IDXFileName);
	    }
	    return successful;
	}

    // Adds a tuple to an index

	private static boolean indexTuple(VAIndexAdapter index, Tuple t, RID rid)
	{
		boolean successful = true;
		try
		{
			Vector100Dtype vd = t.get100DVectFld(index.Index.ColumnID);
			VAEntry entry = index.GetEntry(vd, rid);
			successful = index.insertEntry(entry);
		}
		catch (Exception e)
		{
			System.err.format("Could not create index entry for field number %d\n", index.Index.ColumnID);
			successful = false;
		}
		return successful;
	}
}


